"""
document_loader.py 模块
负责加载不同格式的文档（适配langchain-community，消除弃用警告，使用纯迭代逻辑）
"""
from abc import ABC, abstractmethod
from pathlib import Path
from langchain_community.document_loaders import (
    PyPDFLoader, Docx2txtLoader, UnstructuredMarkdownLoader
)
from langchain.docstore.document import Document  # 用于构造文档对象


class BaseDocumentLoader(ABC):
    """文档加载器基类"""

    @abstractmethod
    def __init__(self, file_path: str):
        self.file_path = file_path

    @abstractmethod
    def load(self):
        """加载文档并返回文档内容"""
        pass


class PDFLoader(BaseDocumentLoader):
    """PDF文档加载器（保持原有逻辑，PyPDFLoader内部为迭代实现）"""

    def __init__(self, file_path: str):
        super().__init__(file_path)
        self.loader = PyPDFLoader(file_path)

    def load(self):
        return self.loader.load()


class TextLoader(BaseDocumentLoader):
    """文本文件加载器（重写为纯迭代逻辑，彻底避免递归）"""

    def __init__(self, file_path: str, encoding: str = "utf-8"):
        super().__init__(file_path)
        self.encoding = encoding  # 支持指定编码

    def load(self):
        """纯迭代读取文本，无任何递归逻辑"""
        docs = []
        try:
            # 按行迭代读取（完全非递归）
            with open(self.file_path, "r", encoding=self.encoding) as f:
                # 读取所有行并合并（迭代操作，无递归）
                lines = []
                for line in f:  # for循环迭代，避免递归
                    lines.append(line.rstrip("\n"))  # 保留换行符的话用 line 即可
                full_text = "\n".join(lines)  # 合并为完整文本

                # 构造LangChain Document对象（兼容后续处理）
                docs.append(Document(
                    page_content=full_text,
                    metadata={"source": self.file_path, "file_type": "txt"}
                ))
            return docs
        except UnicodeDecodeError:
            # 处理编码错误（如gbk编码的文件）
            with open(self.file_path, "r", encoding="gbk", errors="ignore") as f:
                lines = [line.rstrip("\n") for line in f]
                full_text = "\n".join(lines)
                docs.append(Document(
                    page_content=full_text,
                    metadata={"source": self.file_path, "file_type": "txt", "encoding": "gbk"}
                ))
            return docs
        except Exception as e:
            raise RuntimeError(f"文本加载失败：{str(e)}")


class DocxLoader(BaseDocumentLoader):
    """Word文档加载器（保持原有逻辑，内部为迭代实现）"""

    def __init__(self, file_path: str):
        super().__init__(file_path)
        self.loader = Docx2txtLoader(file_path)

    def load(self):
        return self.loader.load()


class MarkdownLoader(BaseDocumentLoader):
    """Markdown文档加载器（保持原有逻辑）"""

    def __init__(self, file_path: str):
        super().__init__(file_path)
        self.loader = UnstructuredMarkdownLoader(file_path)

    def load(self):
        return self.loader.load()


class DocumentLoaderFactory:
    """文档加载器工厂类，根据文件类型返回相应的加载器"""

    @staticmethod
    def get_loader(file_path: str) -> BaseDocumentLoader:
        file_ext = Path(file_path).suffix.lower()

        if file_ext == ".pdf":
            return PDFLoader(file_path)
        elif file_ext == ".md":
            return MarkdownLoader(file_path)
        elif file_ext == ".txt":
            return TextLoader(file_path)
        elif file_ext == ".docx":
            return DocxLoader(file_path)
        else:
            raise ValueError(f"不支持的文件类型: {file_ext}，支持格式：.pdf/.txt/.docx/.md")